package com.blacktry.config;

import com.blacktry.entity.model.Admin;
import com.blacktry.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.session.HttpSessionEventPublisher;

import javax.annotation.Resource;
import javax.servlet.http.HttpSessionListener;


@Configuration
@EnableWebSecurity  //开启MVC Security安全支持
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Resource
    private UserDetailsService userDetailsService;

    @Autowired
    private AdminService adminService;

    //密码编码器
    @Bean
    public PasswordEncoder passwordEncoder(){
        //使用这么一个实现类
        return new BCryptPasswordEncoder();
    }

    @Override
    @Bean
    public UserDetailsService userDetailsService(){
        return username->{
            Admin admin = adminService.getAdminByUserName(username);
            if(null != admin){
                admin.setRoles(adminService.getRoles(admin.getId()));
                return admin;
            }
            throw new UsernameNotFoundException("用户名或密码错误");
        };
    }

    @Bean
    public JwtAuthencationTokenFilter jwtAuthencationTokenFilter(){
        return new JwtAuthencationTokenFilter();
    };

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private RestAuthorizationEntryPoint restAuthorizationEntryPoint;

    @Autowired
    private RestfulAccessDeniedHandler restfulAccessDeniedHandler;

    @Autowired
    private CustomFilter customFilter;

    @Autowired
    private CustomUrlDecisionManager customUrlDecisionManager;

    // 测试时可以打开权限  没有拦截的
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/login","/logout","/css/**","/js/**","/index.html",
                "favicon.ico","/doc.html","/webjars/**","/swagger-resources/**","/v2/api-docs/**","/captcha",
                "/calendar/exportCalendar",
                "/articles/**","/labels/**","/sorts/**");
    }


    //认证  (定义角色)
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService())
                .passwordEncoder(passwordEncoder());
    }


    //授权  (给不同的角色分配不同的权限)
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //关闭csrf跨域-防火墙,使用了JWT不需要csrf了
        http
        .csrf().disable()
        // 基于token不需要Session
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        .authorizeRequests()
        // 以下全部需要认证
        .anyRequest()
        .authenticated()
                // 动态权限配置
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                        object.setAccessDecisionManager(customUrlDecisionManager);  //判断用户角色
                        object.setSecurityMetadataSource(customFilter);  //根据url分析请求所需的角色
                        return object;
                    }
                })
        .and()
        // 禁用缓存
        .headers()
        .cacheControl();
        // 添加jwt 登录授权过滤器
        http.addFilterBefore(jwtAuthencationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
        // 添加自定义未授权和未登录结果返回
        http.exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler)
                .authenticationEntryPoint(restAuthorizationEntryPoint);
        // 限制登录人数
//        http.sessionManagement().maximumSessions(1)
                // 限制只能当前用户登录，默认后来者顶掉前面的
//                .maxSessionsPreventsLogin(true);
    }

    // 监听服务端Session，用来限制登录
    @Bean
    HttpSessionListener sessionListener(){
        return new HttpSessionEventPublisher();
    }
}